import sys
import os
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QPushButton, QLabel, QFileDialog, QTabWidget, QGroupBox, QFormLayout,
    QSpinBox, QLineEdit, QDoubleSpinBox, QMessageBox, QComboBox
)
from PySide6.QtGui import QPixmap, QImage, QPainter, QPen, QColor
from PySide6.QtCore import Qt, QRect
from PIL import Image, ImageDraw
import numpy as np

class ImageCropTool(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("图像裁剪工具")
        self.setGeometry(100, 100, 1000, 800)
        self.image_path = None
        self.original_image = None
        self.processed_image = None
        self.crop_method = "edge"
        self.selection_rect = None
        self.init_ui()

    def init_ui(self):
        # 创建主部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # 创建菜单栏
        self.create_menu_bar()

        # 创建图像显示区域
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignCenter)
        self.image_label.setMinimumSize(600, 400)
        main_layout.addWidget(self.image_label)

        # 创建裁剪方法选择标签页
        self.tab_widget = QTabWidget()
        self.create_edge_crop_tab()
        self.create_coordinate_crop_tab()
        self.create_auto_crop_tab()
        main_layout.addWidget(self.tab_widget)

        # 创建按钮区域
        button_layout = QHBoxLayout()
        self.load_button = QPushButton("加载图像")
        self.load_button.clicked.connect(self.load_image)
        self.crop_button = QPushButton("裁剪图像")
        self.crop_button.clicked.connect(self.crop_image)
        self.save_button = QPushButton("保存图像")
        self.save_button.clicked.connect(self.save_image)
        self.reset_button = QPushButton("重置")
        self.reset_button.clicked.connect(self.reset_image)

        button_layout.addWidget(self.load_button)
        button_layout.addWidget(self.crop_button)
        button_layout.addWidget(self.save_button)
        button_layout.addWidget(self.reset_button)
        main_layout.addLayout(button_layout)

    def create_menu_bar(self):
        menubar = self.menuBar()
        file_menu = menubar.addMenu("文件")
        load_action = file_menu.addAction("加载图像")
        load_action.triggered.connect(self.load_image)
        save_action = file_menu.addAction("保存图像")
        save_action.triggered.connect(self.save_image)
        exit_action = file_menu.addAction("退出")
        exit_action.triggered.connect(self.close)

    def create_edge_crop_tab(self):
        edge_tab = QWidget()
        layout = QFormLayout(edge_tab)

        self.left_spin = QSpinBox()
        self.left_spin.setRange(0, 1000)
        self.right_spin = QSpinBox()
        self.right_spin.setRange(0, 1000)
        self.top_spin = QSpinBox()
        self.top_spin.setRange(0, 1000)
        self.bottom_spin = QSpinBox()
        self.bottom_spin.setRange(0, 1000)

        layout.addRow("左侧裁剪像素:", self.left_spin)
        layout.addRow("右侧裁剪像素:", self.right_spin)
        layout.addRow("顶部裁剪像素:", self.top_spin)
        layout.addRow("底部裁剪像素:", self.bottom_spin)

        self.tab_widget.addTab(edge_tab, "边缘裁剪")

    def create_coordinate_crop_tab(self):
        coord_tab = QWidget()
        layout = QFormLayout(coord_tab)

        self.x1_spin = QSpinBox()
        self.x1_spin.setRange(0, 10000)
        self.y1_spin = QSpinBox()
        self.y1_spin.setRange(0, 10000)
        self.x2_spin = QSpinBox()
        self.x2_spin.setRange(0, 10000)
        self.y2_spin = QSpinBox()
        self.y2_spin.setRange(0, 10000)

        layout.addRow("X1:", self.x1_spin)
        layout.addRow("Y1:", self.y1_spin)
        layout.addRow("X2:", self.x2_spin)
        layout.addRow("Y2:", self.y2_spin)

        self.tab_widget.addTab(coord_tab, "坐标裁剪")

    def create_auto_crop_tab(self):
        auto_tab = QWidget()
        layout = QFormLayout(auto_tab)

        self.edge_spin = QSpinBox()
        self.edge_spin.setRange(0, 1000)
        self.edge_spin.setValue(10)

        self.tolerance_spin = QDoubleSpinBox()
        self.tolerance_spin.setRange(0, 255)
        self.tolerance_spin.setValue(10)
        self.tolerance_spin.setSingleStep(1)

        layout.addRow("边缘扩展像素:", self.edge_spin)
        layout.addRow("颜色容差:", self.tolerance_spin)

        self.tab_widget.addTab(auto_tab, "自动裁剪")

    def load_image(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图像", "", "图像文件 (*.png *.jpg *.jpeg *.tiff *.bmp)")

        if file_path:
            self.image_path = file_path
            try:
                self.original_image = Image.open(file_path)
                self.processed_image = self.original_image.copy()
                self.display_image()
                self.update_coordinate_spins()
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法加载图像: {str(e)}")

    def display_image(self):
        if self.processed_image:
            # 将PIL图像转换为QPixmap
            img = self.processed_image.convert("RGBA")
            data = img.tobytes("raw", "RGBA")
            qim = QImage(data, img.width, img.height, QImage.Format_RGBA8888)
            pixmap = QPixmap.fromImage(qim)

            # 调整图像大小以适应显示区域
            scaled_pixmap = pixmap.scaled(
                self.image_label.width(), self.image_label.height(),
                Qt.KeepAspectRatio, Qt.SmoothTransformation
            )
            self.image_label.setPixmap(scaled_pixmap)

    def update_coordinate_spins(self):
        if self.original_image:
            width, height = self.original_image.size
            self.x2_spin.setValue(width)
            self.y2_spin.setValue(height)

    def crop_image(self):
        if not self.original_image:
            QMessageBox.warning(self, "警告", "请先加载图像")
            return

        try:
            crop_method = self.tab_widget.currentIndex()
            if crop_method == 0:  # 边缘裁剪
                left = self.left_spin.value()
                right = self.right_spin.value()
                top = self.top_spin.value()
                bottom = self.bottom_spin.value()
                self.crop_by_edges(left, right, top, bottom)
            elif crop_method == 1:  # 坐标裁剪
                x1 = self.x1_spin.value()
                y1 = self.y1_spin.value()
                x2 = self.x2_spin.value()
                y2 = self.y2_spin.value()
                self.crop_by_coordinates(x1, y1, x2, y2)
            elif crop_method == 2:  # 自动裁剪
                edge = self.edge_spin.value()
                tolerance = self.tolerance_spin.value()
                self.crop_auto(edge, tolerance)

            self.display_image()
            QMessageBox.information(self, "成功", "图像裁剪完成")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"裁剪失败: {str(e)}")

    def crop_by_edges(self, left, right, top, bottom):
        if self.original_image:
            width, height = self.original_image.size
            new_width = width - left - right
            new_height = height - top - bottom

            if new_width <= 0 or new_height <= 0:
                raise ValueError("裁剪区域过大，无法生成有效图像")

            self.processed_image = self.original_image.crop((
                left, top, width - right, height - bottom
            ))

    def crop_by_coordinates(self, x1, y1, x2, y2):
        if self.original_image:
            if x1 >= x2 or y1 >= y2:
                raise ValueError("无效的坐标值")

            self.processed_image = self.original_image.crop((x1, y1, x2, y2))

    def crop_auto(self, edge=10, tolerance=10):
        if self.original_image:
            # 将图像转换为RGBA模式以处理透明度
            img = self.original_image.convert("RGBA")
            pixels = np.array(img)

            # 获取非透明、非白色的像素
            alpha_channel = pixels[:, :, 3]
            non_transparent = alpha_channel > tolerance

            # 检测非白色像素
            r, g, b = pixels[:, :, 0], pixels[:, :, 1], pixels[:, :, 2]
            non_white = (r < 255 - tolerance) | (g < 255 - tolerance) | (b < 255 - tolerance)

            # 组合条件
            mask = non_transparent & non_white

            if not np.any(mask):
                raise ValueError("未找到有效内容区域")

            # 找到边界
            coords = np.argwhere(mask)
            y_min, x_min = coords.min(axis=0)
            y_max, x_max = coords.max(axis=0)

            # 添加边缘
            y_min = max(0, y_min - edge)
            x_min = max(0, x_min - edge)
            y_max = min(img.height - 1, y_max + edge)
            x_max = min(img.width - 1, x_max + edge)

            # 裁剪图像
            self.processed_image = self.original_image.crop((x_min, y_min, x_max + 1, y_max + 1))

    def save_image(self):
        if not self.processed_image:
            QMessageBox.warning(self, "警告", "没有可保存的图像")
            return

        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存图像", "", "PNG文件 (*.png);;JPEG文件 (*.jpg);;TIFF文件 (*.tiff);;所有文件 (*)")

        if file_path:
            try:
                # 处理透明通道（如果是PNG）
                if file_path.lower().endswith(".png"):
                    self.processed_image.save(file_path, "PNG")
                else:
                    # 对于非PNG格式，转换为RGB模式
                    rgb_image = self.processed_image.convert("RGB")
                    rgb_image.save(file_path)
                QMessageBox.information(self, "成功", "图像保存成功")
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法保存图像: {str(e)}")

    def reset_image(self):
        if self.original_image:
            self.processed_image = self.original_image.copy()
            self.display_image()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ImageCropTool()
    window.show()
    sys.exit(app.exec())